package cz.myslivec.slovicka.util.converter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Abstract converter base to general conversion between two elements.
 * 
 * @author myslivec
 *
 * @param <F> Type of from-element
 * @param <T> Type of to-element
 */
public abstract class AConverterBase<F, T> {

	/**
	 * Converts given from-element collection to result-element list.
	 * 
	 * @param fromElements - list to convert
	 * @return converted list
	 */
	public final List<T> convertList(Collection<F> fromElements) {
		if(fromElements == null) {
			return null;
		}
		List<T> toElements = new ArrayList<T>();
		for(F element : fromElements) {
			toElements.add(convert(element));
		}
		return toElements;
	}
	
	/**
	 * Reverse conversion of collection.
	 * 
	 * @param toElements - list to convert
	 * @return converted list
	 */
	public final List<F> convertBackList(Collection<T> toElements) {
		if(toElements == null) {
			return null;
		}
		List<F> fromElements = new ArrayList<F>();
		for(T element : toElements) {
			fromElements.add(convertBack(element));
		}
		return fromElements;
	}
	
	/**
	 * Converts given from-element to result-element.
	 * 
	 * @param from - element to convert
	 * @return converted element
	 */
	public final T convert(F from) {
		if(from == null) {
			return null;
		}
		T result = getToInstance();
		result = getTo(result, from);
		return result;
	}
	
	/**
	 * Reverse conversion.
	 *  
	 * @param to - element to convert
	 * @return converted element
	 */
	public final F convertBack(T to) {
		if(to == null) {
			return null;
		}
		F result = getFromInstance();
		result = getFrom(result, to);
		return result;
	}
	
	/**
	 * Transforms from-element to given result instance.
	 * Used in @see {cz.aag.util.convert.AConverterBase#convert(F from)}
	 * 
	 * @param result - instance of result
	 * @param from
	 * @return transformed element
	 */
	protected abstract T getTo(T result, F from);
	
	/**
	 * Transforms from-element to given result instance.
	 * Used in @see {cz.aag.util.convert.AConverterBase#convertBack(T to)}
	 * 
	 * @param result - instance of result
	 * @param to
	 * @return transformed element
	 */
	protected abstract F getFrom(F result, T to);

	/**
	 * Gives instance of result's element.
	 * Used in @see {cz.aag.util.convert.AConverterBase#convert(F from)}
	 * 
	 * @return to-element instance
	 */
	protected abstract T getToInstance();
	
	/**
	 * Gives instance of transformed element.
	 * Used in @see {cz.aag.util.convert.AConverterBase#convertBack(T to)}
	 * 
	 * @return from-element instance
	 */
	protected abstract F getFromInstance();
}
